package com.yeyks.commonReference.append.wxPay.service;

import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.google.common.collect.Maps;
import com.yeyks.common.em.pay.PayTypeEnum;
import com.yeyks.common.exception.ServiceException;
import com.yeyks.common.utils.ObjectConvertUtil;
import com.yeyks.common.utils.OkHttpUtil;
import com.yeyks.commonReference.append.wxPay.config.WeChatYyksBaseConfig;
import com.yeyks.commonReference.append.wxPay.config.WeChatYyksBaseConfigUtil;
import com.yeyks.commonReference.append.wxPay.config.WeChatYyksConfigUtil;
import com.yeyks.commonReference.append.wxPay.dto.WxPayParam;
import com.yeyks.commonReference.append.wxPay.dto.WxRefundParam;
import com.yeyks.commonReference.append.wxPay.pojo.param.WXMpWechatOrderStatusParam;
import com.yeyks.commonReference.append.wxPay.pojo.vo.WXMpWechatOrderStatusVo;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * @Author fuchangshuai
 * @date 2019/4/12 3:08 PM
 */
@Slf4j
@Service
public class WeiXinPayService {
    @Autowired
    private WeChatYyksBaseConfig wxConfig;
    @Autowired
    private OkHttpClient okHttpClient;
    @Autowired
    private WeChatYyksBaseConfigUtil weChatYyksBaseConfigUtil;
    @Autowired
    private WeChatYyksConfigUtil weChatYyksConfigUtil;

    /**
     * 微信下单:3.3.a
     *
     * @param payParam
     * @return
     */
    public Map<String, Object> generateWeChatOrders(WxPayParam payParam) {
        try {
            WxPayService wxPayService = weChatYyksConfigUtil.getWxPayService(payParam.getOrderType(), payParam.getType());
            //生成预支付订单
            WxPayUnifiedOrderRequest prepayInfo = WxPayUnifiedOrderRequest.newBuilder()
                    .openid(payParam.getOpenId())
                    .outTradeNo(payParam.getOrderNo())
                    .totalFee(payParam.getTotalFee())
                    .body(payParam.getBody())
                    .tradeType(payParam.getTradeType())
                    .spbillCreateIp(payParam.getCreateIp())
                    .notifyUrl(payParam.getNotifyUrl())
                    .attach(payParam.getAttach())
                    .build();
            WxPayMpOrderResult unifiedOrder = null;
            try {
                unifiedOrder = wxPayService.createOrder(prepayInfo);
            } catch (WxPayException e) {
                e.printStackTrace();
            }
            log.info("微信支付订单返回结果信息result = {}", unifiedOrder);
            Map<String, Object> map = ObjectConvertUtil.objectToMap(unifiedOrder);
            if (map == null) {
                return new HashMap<>();
            }
            map.put("package", map.get("packageValue"));
            map.remove("packageValue");
            return map;
        } catch (Exception e) {
            log.error("转换支付map失败{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
        return new HashMap<>();
    }

    /**
     * 通过code和type(gzh或xcx,默认gzh)获取微信openId
     * <p>
     * "access_token":"ACCESS_TOKEN",
     * "expires_in":7200,
     * "refresh_token":"REFRESH_TOKEN",
     * "openid":"OPENID",
     * "scope":"SCOPE"
     *
     * @param code
     * @param type
     * @return
     */
    public String getOpenId(String code, String type) {
        try {
            String url = wxConfig.getOpenIdUrl(type, code);
            String response = OkHttpUtil.get(okHttpClient, url);
            JSONObject jsonObject = JSONObject.parseObject(response);
            return (String) jsonObject.get("openid");
        } catch (Exception e) {
            log.info("获取openId失败{}", e.getLocalizedMessage());
        }
        return null;
    }

    /**
     * 微信app支付
     *
     * @param payParam
     * @return
     */
    public WxPayAppOrderResult appPay(WxPayParam payParam) {
        WxPayService wxPayService = weChatYyksConfigUtil.getWxPayService(payParam.getOrderType(), payParam.getType());
        WxPayAppOrderResult result = null;
        try {
            //生成预支付订单
            WxPayUnifiedOrderRequest prepayInfo = WxPayUnifiedOrderRequest.newBuilder()
                    .outTradeNo(payParam.getOrderNo())
                    .totalFee(payParam.getTotalFee())
                    .body(payParam.getBody())
                    .tradeType(payParam.getTradeType())
                    .spbillCreateIp(payParam.getCreateIp())
                    .notifyUrl(payParam.getNotifyUrl())
                    .attach(payParam.getAttach())
                    .build();
            result = wxPayService.createOrder(prepayInfo);
        } catch (Exception e) {
            log.error("微信支付失败！订单号：{},原因:{}", payParam.getOrderNo(), e.getMessage());
            e.printStackTrace();
        }
        log.info("微信订单退款返回信息result = {}", result);
        return result;
    }

    /**
     * 微信h5支付
     *
     * @param payParam
     * @return
     */
    public WxPayMwebOrderResult h5Pay(WxPayParam payParam) {
        WxPayService wxPayService = weChatYyksConfigUtil.getWxPayService(payParam.getOrderType(), payParam.getType());
        WxPayMwebOrderResult result = null;
        try {
            //生成预支付订单
            WxPayUnifiedOrderRequest prepayInfo = WxPayUnifiedOrderRequest.newBuilder()
                    .outTradeNo(payParam.getOrderNo())
                    .totalFee(payParam.getTotalFee())
                    .body(payParam.getBody())
                    .tradeType(payParam.getTradeType())
                    .spbillCreateIp(payParam.getCreateIp())
                    .notifyUrl(payParam.getNotifyUrl())
                    .attach(payParam.getAttach())
                    .build();
            result = wxPayService.createOrder(prepayInfo);
        } catch (Exception e) {
            log.error("微信支付失败！订单号：{},原因:{}", payParam.getOrderNo(), e.getMessage());
            e.printStackTrace();
        }
        log.info("微信订单退款返回信息result = {}", result);
        return result;
    }


    /**
     * 订单退款
     *
     * @param wxRefundParam
     * @return WxPayRefundResult
     */
    public WxPayRefundResult refund(WxRefundParam wxRefundParam) {
        WxPayService wxPayService = weChatYyksBaseConfigUtil.getWxPayService(wxRefundParam.getType());
        WxPayRefundResult result = null;
        try {
            //生成预支付订单
            WxPayRefundRequest refundRequest = WxPayRefundRequest.newBuilder()
                    .outTradeNo(wxRefundParam.getOutTradeNo())
                    .outRefundNo(wxRefundParam.getOutRefundNo())
                    .totalFee(wxRefundParam.getTotalFee())
                    .refundFee(wxRefundParam.getRefundFee())
                    .build();
            result = wxPayService.refund(refundRequest);
        } catch (Exception e) {
            log.error("微信支付失败！订单号：{},原因:{}", wxRefundParam.getOutTradeNo(), e.getMessage());
            e.printStackTrace();
        }
        log.info("微信订单退款返回信息result = {}", result);
        return result;
    }

    /**
     * 订单退款
     *
     * @param wxRefundParam
     * @return boolean
     */
    public Boolean disPoseRefund(WxRefundParam wxRefundParam) {
        try {
            WxPayRefundResult refund = refund(wxRefundParam);
            if (refund == null) {
                log.error("订单退款返回数据为空");
                return false;
            }
            if (refund.getResultCode().equals("SUCCESS")
                    && refund.getRefundFee().equals(wxRefundParam.getRefundFee())) {
                return true;
            } else {
                log.error("订单退款失败{}", JSONObject.toJSONString(refund));
                return false;
            }
        } catch (Exception e) {
            log.error("订单退款异常{}", e.getLocalizedMessage());
            return false;
        }
    }

    /**
     * 将返回的map格式修改一下
     *
     * @param payParam
     * @return
     */
    public Map<String, String> appDisposePay(WxPayParam payParam) {
        Map<String, String> result = Maps.newHashMap();
        try {
            WxPayAppOrderResult resultDTO = appPay(payParam);
            result.put("appid", resultDTO.getAppId());
            result.put("noncestr", resultDTO.getNonceStr());
            result.put("package", resultDTO.getPackageValue());
            result.put("partnerid", resultDTO.getPartnerId());
            result.put("prepayid", resultDTO.getPrepayId());
            result.put("timestamp", resultDTO.getTimeStamp());
            result.put("sign", resultDTO.getSign());
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 微信提现
     *
     * @param payParam
     * @return
     */
    public EntPayResult wxExtract(WxPayParam payParam) {
        WxPayService wxPayService = weChatYyksBaseConfigUtil.getWxPayService(payParam.getType());
        EntPayRequest request = EntPayRequest.newBuilder()
                .partnerTradeNo(payParam.getOrderNo())
                .openid(payParam.getOpenId())
                .checkName("NO_CHECK")
                .amount(payParam.getTotalFee())
                .description("提现")
                .spbillCreateIp(payParam.getCreateIp())
                .reUserName("yyks")
                .build();
        EntPayResult result = null;
        try {
            result = wxPayService.getEntPayService().entPay(request);
        } catch (WxPayException e) {
            if ("AMOUNT_LIMIT".equals(e.getErrCode()) || "NO_AUTH".equals(e.getErrCode())) {
                throw new ServiceException(e.getErrCodeDes());
            }
            throw new ServiceException("提现失败");
        } catch (Throwable e) {
            e.printStackTrace();
            throw new ServiceException("提现失败");
        }
        return result;
    }

    /**
     * 微信提现
     *
     * @return
     */
    public Boolean disposeWxExtract(String orderNo, String openId, Integer totalFee, String ip, String type) {
        WxPayParam wxPayParam = new WxPayParam();
        wxPayParam.setOrderNo(orderNo);
        wxPayParam.setOpenId(openId);
        wxPayParam.setTotalFee(totalFee);
        wxPayParam.setCreateIp(ip);
        wxPayParam.setType(type);
        try {
            wxExtract(wxPayParam);
        } catch (ServiceException e) {
            throw new ServiceException(e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    //微信订单状态:v4.5
    public WXMpWechatOrderStatusVo wechatOrderStatus(WXMpWechatOrderStatusParam param) {
        try {
            WxPayService wxPayService = weChatYyksConfigUtil.getWxPayService(null, PayTypeEnum.getDesc(param.getType()));
            WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(null, param.getOrderNo());
            return new WXMpWechatOrderStatusVo().setStatus(wxPayOrderQueryResult.getTradeState());
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw new ServiceException("查询失败");
    }

}
